#include <iostream>
#include <unordered_map>
#include <functional>
#include <memory>
#include <vector>
#include <unistd.h>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class Timer
{
private:
    uint64_t _id;         // 定时器任务id
    uint32_t _timeout;    // 定时器超时时间
    bool _canceled;       // 定时器是否被取消
    TaskFunc _task_cb;    // 定时器超时时应该执行的任务函数
    ReleaseFunc _release; // 定时器超时时除了要执行任务函数之外，还需要把哈希表中的weak_ptr销毁

public:
    Timer(uint64_t id, uint32_t timeout, TaskFunc task_cb)
        : _id(id), _timeout(timeout), _task_cb(task_cb), _canceled(false)
    {
    }

    ~Timer()
    {
        // 定时器如果未被取消，则执行定时任务
        if (_canceled == false)
            _task_cb();

        // 释放时间轮中保存的weak_ptr定时器对象信息
        _release();
    }

    // 设置回调函数执行释放时间轮中保存的weak_ptr定时器对象信息
    void setDestructor(ReleaseFunc cb)
    {
        _release = cb;
    }

    // 获取超时时间
    int timeOut()
    {
        return _timeout;
    }

    // 取消定时器任务
    void cancel()
    {
        _canceled = true;
    }
};

class TimerWheel
{
private:
    int _tick;     // 秒针
    int _capacity; // 表盘最大刻度 - 最大延迟时间

    // 时间轮需要管理多个Timer对象，这里使用哈希表进行管理(id - weak_ptr<Timer>) 使用weak_ptr是因为不会增加引用计数
    std::unordered_map<uint64_t, std::weak_ptr<Timer>> _timers;

    // 保存多个Timer对象的shared_ptr，实现秒级时间轮
    std::vector<std::vector<std::shared_ptr<Timer>>> _wheel;

private:
    void releaseWeakPtr(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
            _timers.erase(id);
    }

public:
    TimerWheel()
        : _tick(0), _capacity(60), _wheel(_capacity)
    {
    }
    ~TimerWheel()
    {
    }

    bool hasTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            return true;
        }
        return false;
    }

    // 添加定时任务
    void addTimer(uint64_t id, uint32_t timeout, TaskFunc task_cb)
    {
        std::shared_ptr<Timer> sp(new Timer(id, timeout, task_cb));

        sp->setDestructor(std::bind(&TimerWheel::releaseWeakPtr, this, id));

        int pos = (_tick + timeout) % _capacity;
        _wheel[pos].push_back(sp);

        _timers[id] = std::weak_ptr<Timer>(sp);
    }

    // 刷新定时任务
    void reflushTimer(uint64_t id)
    {
        // 通过保存的定时器对象的weak_ptr构造一个shared_ptr出来，添加到轮子中
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;

        // lock()获取weak_ptr中管理的对象对应的shared_ptr;
        std::shared_ptr<Timer> sp = it->second.lock();

        int delay = sp->timeOut();
        int pos = (_tick + delay) % _capacity;

        _wheel[pos].push_back(sp);
    }

    // 这个函数处理每秒钟执行一次，相当于秒钟向后走了一步
    void runTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        // 清空指定位置的数组，就会把数组中保存的所有管理定时器对象的shared_ptr释放掉
        _wheel[_tick].clear();
    }

    // 取消定时任务
    void cancelTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;
        std::shared_ptr<Timer> sp = it->second.lock();
        if (sp)
            sp->cancel();
    }
};

// 测试
class Test
{
public:
    Test() { std::cout << "构造" << std::endl; }
    ~Test() { std::cout << "析构" << std::endl; }
};

void DelTest(Test *t)
{
    delete t;
}

int main()
{
    TimerWheel tw;

    Test *t = new Test();
    int id = 6;

    tw.addTimer(id, 5, std::bind(&DelTest, t));

    for (int i = 0; i < 5; i++)
    {
        sleep(1);
        tw.reflushTimer(id);
        std::cout << "刷新了⼀下3号定时任务!\n";
        tw.runTimerTask();
    }

    std::cout << "刷新定时任务停⽌, 5s后释放任务将被执⾏\n";
    while (1)
    {
        std::cout << "--------------------\n";
        sleep(1);
        tw.runTimerTask(); // 每秒调用⼀次，模拟定时器
        if (tw.hasTimer(id) == false)
        {
            std::cout << "定时任务已经被执⾏完毕！\n";
            break;
        }
    }
    return 0;
}
